#include "Metaballs2D.h"
#include "MetaballsTable.h"

namespace blobDetection
{

Metaballs2D::~Metaballs2D()
{
	delete [] gridValue;
	delete [] edgeVrt;
	delete [] voxel;
	delete [] lineToDraw;
}

// init(int, int)
// ------------------
void Metaballs2D::init(int resx, int resy)
{
	this->resx = resx;
	this->resy = resy;

	this->stepx = 1.0f/( (float)(resx-1));
	this->stepy = 1.0f/( (float)(resy-1));

	// Allocate gridValue
	nbGridValue	= resx*resy;
	gridValue	= new float[nbGridValue];

	// Allocate voxels
	nbVoxel		= nbGridValue;
	voxel		= new int[nbVoxel];

	// Allocate EdgeVertices
     edgeVrt 	= new EdgeVertex [2*nbVoxel];
     nbEdgeVrt 	= 2*nbVoxel;

	// Allocate Lines
	lineToDraw 		= new int[2*nbVoxel];
     nbLineToDraw 	= 0;
	
     // Precompute some values
	int x,y,n,index;
	n = 0;
	for (x=0 ; x<resx ; x++)
		for (y=0 ; y<resy ; y++)
		{
			index = 2*n;
			// index to edgeVrt
                     voxel[x+resx*y] = index;
			// values
                     edgeVrt[index].setCoordinates(x*stepx, y*stepy);
                     edgeVrt[index+1].setCoordinates(x*stepx, y*stepy);

			// Next!
			n++;
		}
	
}

// computeIsovalue()
// ------------------
void Metaballs2D::computeIsovalue()
{         
}


// computeMesh()
// ------------------
void Metaballs2D::computeMesh()
{
	// Compute IsoValue
	computeIsovalue();
	// Get Lines indices

	int					x,y,squareIndex,n;
	int					iEdge;
	int					offx, offy, offAB;
	int					toCompute;
	int					offset;
	float					t;
	float					vx,vy;
	int edgeOffsetInfo[3];

	nbLineToDraw = 0;
	vx	     = 0.0f;
	for (x=0 ; x<resx-1 ; x++)
	{
		vy = 0.0f;
		for (y=0 ; y<resy-1 ; y++)
		{
			offset		= x + resx*y;
			squareIndex = getSquareIndex(x,y);

			n	        = 0;
			while ( (iEdge = MetaballsTable::edgeCut[squareIndex][n++]) != -1)
			{
				edgeOffsetInfo[0]          = MetaballsTable::edgeOffsetInfo[iEdge][0];
				edgeOffsetInfo[1]          = MetaballsTable::edgeOffsetInfo[iEdge][1];
				edgeOffsetInfo[2]          = MetaballsTable::edgeOffsetInfo[iEdge][2];
				offx			= edgeOffsetInfo[0];
				offy			= edgeOffsetInfo[1];
				offAB			= edgeOffsetInfo[2];

                            lineToDraw[nbLineToDraw++] = voxel[(x+offx) + resx*(y+offy)] + offAB;
			}

            toCompute = MetaballsTable::edgeToCompute[squareIndex];
			if (toCompute>0)
			{
                if ( (toCompute & 1) > 0) // Edge 0
				{
					t	= (isovalue - gridValue[offset]) / (gridValue[offset+1] - gridValue[offset]); 
					edgeVrt[voxel[offset]].x = vx*(1.0f-t) + t*(vx+stepx);
                             }
				if ( (toCompute & 2) > 0) // Edge 3
				{
					t	= (isovalue - gridValue[offset]) / (gridValue[offset+resx] - gridValue[offset]); 
					edgeVrt[voxel[offset]+1].y = vy*(1.0f-t) + t*(vy+stepy);
				}
			
			} // toCompute
			vy += stepy;
		}	// for y

		vx += stepx;
	}	// for x

	nbLineToDraw /= 2;
 
}

// getSquareIndex(int,int)
// ------------------
int Metaballs2D::getSquareIndex(int x, int y)
{
	int squareIndex = 0;
    int offy  = resx*y;
    int offy1 = resx*(y+1);
	if (gridValue[x+offy]		< isovalue) squareIndex |= 1;
	if (gridValue[x+1+offy]		< isovalue) squareIndex |= 2;
	if (gridValue[x+1+offy1]	< isovalue) squareIndex |= 4;
	if (gridValue[x+offy1]		< isovalue) squareIndex |= 8;
	return squareIndex;
}

// setIsoValue(float)
// ------------------
void Metaballs2D::setIsovalue(float iso)
{
	this->isovalue = iso;
}



}